package com.towker.core.log;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Properties;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import org.apache.commons.dbcp.BasicDataSource;
import org.apache.commons.dbcp.BasicDataSourceFactory;
import org.apache.log4j.jdbc.JDBCAppender;
import org.apache.log4j.spi.ErrorCode;
import org.apache.log4j.spi.LoggingEvent;


/**
 * 
 * log4j��־д�뵽��ݿ� д����ݿ�Ĺ������:��־��Ϣ�ĸ�ʽҪ��������Ķ����Ҽ�(��, 
 * �4α�ʾ�û���(executor),ϵͳID(systemId),����(type),��־��Ϣ(content) ��:<admin> <123> <login> <�û���¼�ɹ�> 
 * ÿ�Լ�(��֮��Ĳ��ֽ�������.
 * @author lxh
 */
public class Log4jConnectionPoolJDBCAppender extends JDBCAppender
{
	private static BasicDataSource dataSource = null;
	
	//��
	private String driverClassName="";
	//��ݿ�l��
	private String url="";
	//l����ݿ���û���
	private String username=""; 
	//l����ݿ������
	private String password="";
	// ���l����
	private String maxActive= "30";
	// ������l��
	private String maxIdle="10";
	// ��ʱ�ȴ�ʱ���Ժ���Ϊ��λ
	private String maxWait="10000";
	//ɾ������l��
	private String removeAbandoned="false";
	
	//��ʱʱ��(������Ϊ��λ) 
	private String  removeAbandonedTimeout="120";
	
	public Log4jConnectionPoolJDBCAppender()
	{
		super();
	}

	/**
	 * Adds the event to the buffer. When full the buffer is flushed.
	 */
	@Override
	public void append(LoggingEvent event)
	{
		buffer.add(event);
		if (buffer.size() >= bufferSize)
			flushBuffer();
	}

	/**
	 * Override this to return the connection to a pool, or to clean up the resource. The default behavior holds a single connection open until the appender is closed (typically when garbage collected).
	 */
	@Override
	protected void closeConnection(Connection con)
	{
		try
		{
			con.close();
		}
		catch (SQLException e)
		{
			e.printStackTrace();
		}
	}

	/**
	 * Override this to link with your connection pooling system. By default this creates a single connection which is held open until the object is garbage collected.
	 */
	@Override
	protected Connection getConnection() throws SQLException
	{
		if(dataSource==null)
		{
			try {
				getDataSource();
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}
		
		Connection conn = null;
		if (dataSource != null) {
			conn = dataSource.getConnection();
		}
		return conn;

	}

	/**
	 * ����ɵ�sql����ٽ��д���,���û���(executor),ϵͳID(systemId),����(type),��־��Ϣ(content)�ĸ����Ե����ݽ��д���, �ĸ����Էֱ�ȡ��1,2,3,4���(���������.���Logger�������־��Ϣģʽ����ȷ�����ؿ��ַ�
	 * @param sql
	 * @return
	 */
	private String formatSql(String sql)
	{
		String s = "";
		ArrayList<String> list = new ArrayList<String>();
		try
		{
			Pattern regex = Pattern.compile("(['\"])(.*?)\\1", Pattern.CANON_EQ | Pattern.DOTALL | Pattern.CASE_INSENSITIVE
					| Pattern.UNICODE_CASE | Pattern.MULTILINE);
			Matcher regexMatcher = regex.matcher(sql);
			if (regexMatcher.find())
			{
				s = regexMatcher.group(2);
			}
			else
			{
				return "";
			}
			regex = Pattern.compile("<(.*?)>", Pattern.CANON_EQ | Pattern.DOTALL | Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE
					| Pattern.MULTILINE);
			regexMatcher = regex.matcher(s);
			while (regexMatcher.find())
			{
				list.add(regexMatcher.group(1));
			}
			if (list.size() != 5) return "";
			 
			for (int i = 0; i < 5; i++)
				sql = sql.replaceFirst(s, list.get(i));
			 
		}
		catch (PatternSyntaxException ex)
		{
			return "";
		}
		return sql;
	}

	/**
	 * ��дˢ�»��淽��,����ɵ�SQL�����д��?���Ƿ�д����ݿ�
	 */
	@Override
	public void flushBuffer()
	{
		// Do the actual logging
		removes.ensureCapacity(buffer.size());
		for (Iterator i = buffer.iterator(); i.hasNext();)
		{
			try
			{
				LoggingEvent logEvent = (LoggingEvent) i.next();
				String sql = getLogStatement(logEvent);
				sql = formatSql(sql);
				if (sql != null && sql.length() != 0)
				{
					execute(sql);
				}
				removes.add(logEvent);
			}
			catch (SQLException e)
			{
				errorHandler.error("Failed to excute sql", e, ErrorCode.FLUSH_FAILURE);
			}
		}
		// remove from the buffer any events that were reported
		buffer.removeAll(removes);
		// clear the buffer of reported events
		removes.clear();
	}

	
	
	
	private void getDataSource() throws Exception
	{
		if(dataSource==null)
		{
			Properties p = new Properties();
			p.setProperty("driverClassName",driverClassName); 
			p.setProperty("url", url); 
			p.setProperty("password", password); 
			p.setProperty("username", username); 
			p.setProperty("maxActive", maxActive); 
			p.setProperty("maxIdle",maxIdle); 
			p.setProperty("maxWait", "1000"); 
			p.setProperty("removeAbandoned",removeAbandoned);
			p.setProperty("removeAbandonedTimeout",removeAbandonedTimeout);//��ʱʱ��(������Ϊ��λ)
			p.setProperty("testOnBorrow", "true");
			p.setProperty("logAbandoned", "true");
			
			dataSource = (BasicDataSource) BasicDataSourceFactory
			  .createDataSource(p);//�������Դ�� 
		}
	}
	
	
	
	public String getDriverClassName() {
		return driverClassName;
	}

	public void setDriverClassName(String driverClassName) {
		this.driverClassName = driverClassName;
	}

	public String getUrl() {
		return url;
	}

	public void setUrl(String url) {
		this.url = url;
	}

	public String getUsername() {
		return username;
	}

	public void setUsername(String username) {
		this.username = username;
	}

	public String getPassword() {
		return password;
	}

	public void setPassword(String password) {
		this.password = password;
	}

	public String getMaxActive() {
		return maxActive;
	}

	public void setMaxActive(String maxActive) {
		this.maxActive = maxActive;
	}

	public String getMaxIdle() {
		return maxIdle;
	}

	public void setMaxIdle(String maxIdle) {
		this.maxIdle = maxIdle;
	}

	public String getMaxWait() {
		return maxWait;
	}

	public void setMaxWait(String maxWait) {
		this.maxWait = maxWait;
	}

	public String getRemoveAbandoned() {
		return removeAbandoned;
	}

	public void setRemoveAbandoned(String removeAbandoned) {
		this.removeAbandoned = removeAbandoned;
	}

	public String getRemoveAbandonedTimeout() {
		return removeAbandonedTimeout;
	}

	public void setRemoveAbandonedTimeout(String removeAbandonedTimeout) {
		this.removeAbandonedTimeout = removeAbandonedTimeout;
	}

	public static void setDataSource(BasicDataSource dataSource) {
		Log4jConnectionPoolJDBCAppender.dataSource = dataSource;
	}

	 


}
